package com.qhx.common.service.contract;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import org.fisco.bcos.sdk.abi.ABICodecException;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException;

import java.util.List;



public  abstract class ContractService
{
    protected  String contractAddress;
    protected  String ABI;
    protected String BIN;


    protected  String SM_BIN;

    protected Client client;


    protected AssembleTransactionProcessor txProcessor;

    protected ContractService(Client client,String ABI,String BIN,String contractAddress){
        this(client);
        this.ABI = ABI;
        this.BIN = BIN;
        this.contractAddress = contractAddress;
    }

    protected ContractService(Client client){
        try
        {
            this.client = client;
            this.init();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private void init() throws Exception
    {
        this.txProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client,client.getCryptoSuite().getCryptoKeyPair());
    }



    public ContractService deploy(List<Object> params){
        try
        {
            TransactionResponse response = _deploy(params);
            this.contractAddress = response.getContractAddress();
            return this;
        } catch (ABICodecException e)
        {
            e.printStackTrace();
            return null;
        }
    }

    
    public ContractResponse callFuncGetValues(String funcName, List<Object> funcParams){
        CallResponse response = callFunc(funcName, funcParams);
        ContractResponse res = new ContractResponse();
        if(response.getReturnMessage().equals("Success"))
        {
            JSONArray resAry = JSONUtil.parseArray(response.getValues());
            if(resAry.size() == 0){
                res.setVals(null);
            }else{
                res.setVals(resAry);
            }
            res.setMes(null); 
        }else{
            res.setVals(null);
            res.setMes(response.getReturnMessage());
        }
        return res;
    }

    public ContractResponse sendTranGetValues(String funcName, List<Object> funcParams)
    {
        TransactionResponse response = sendTran(funcName, funcParams);
        ContractResponse res = new ContractResponse();
        if(response.getReturnMessage().equals("Success"))
        {
            JSONArray resAry = JSONUtil.parseArray(response.getValues());
            if(resAry.size() == 0){
                res.setVals(null);
            }else{
                res.setVals(resAry);
            }
            res.setMes(null); 
        }else{
            res.setVals(null);
            res.setMes(response.getReturnMessage());
        }
        return res;

    }


    protected CallResponse callFunc(String funcName, List<Object> funcParams)
    {
        try
        {
            return _callFunc(funcName,funcParams);
        } catch (ABICodecException e) 
        {
            CallResponse callResponse = new CallResponse();
            callResponse.setReturnMessage("ABI异常:"+e.getMessage());
            return callResponse;
        } catch (TransactionBaseException e)
        {
            CallResponse callResponse = new CallResponse();
            callResponse.setReturnMessage("合约异常:"+e.getMessage());
            return callResponse;
        }
    }

    protected TransactionResponse  sendTran(String funcName, List<Object> funcParams){
        try
        {
            return   this._sendTran(funcName, funcParams);
        } catch (ABICodecException e)
        {
            e.printStackTrace();
            TransactionResponse transactionResponse = new TransactionResponse();
            transactionResponse.setValues(null);
            transactionResponse.setReturnMessage(e.getMessage());
            return transactionResponse;
        } catch (TransactionBaseException e)
        {
            e.printStackTrace();
            TransactionResponse transactionResponse = new TransactionResponse();
            transactionResponse.setValues(null);
            transactionResponse.setReturnMessage(e.getMessage());
            return transactionResponse;
        }
    }


    private TransactionResponse _sendTran(String funcName, List<Object> funcParams) throws ABICodecException, TransactionBaseException
    {
        return  this.txProcessor.sendTransactionAndGetResponse(this.contractAddress, this.ABI,
                funcName,funcParams);
    }

    private CallResponse _callFunc(String funcName, List<Object> funcParams) throws ABICodecException, TransactionBaseException
    {
        return this.txProcessor.sendCall(this.client.getCryptoSuite().getCryptoKeyPair().getAddress(),this.contractAddress
                ,ABI,funcName,funcParams);
    }

    private TransactionResponse _deploy(List<Object> params) throws ABICodecException
    {
        return this.txProcessor.deployAndGetResponse(ABI,getBin(client.getCryptoSuite()),params);
    }

    private String getBin(CryptoSuite cryptoSuite){
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BIN : SM_BIN);
    }

    
    public void setSM_BIN(String SM_BIN){
        this.SM_BIN =SM_BIN;
    }

    protected void setAbiBinCon(String abi, String bin, String contractAddress)
    {
        this.ABI = abi;
        this.BIN = bin;
        this.contractAddress = contractAddress;
    }

    public String getContractAddress(){
        return contractAddress;
    }


}